﻿namespace Sai.Test
{
    using Sai.Core;
    using Sai.Core.Introspection;
    using Sai.Test.XUnit;
    using Xunit;

	public class AssemblyDifferenceFacts
	{
		public class TheAsXmlMethod
		{
			[Fact, InMemoryTest]
			public void Creates_MultiLine_Format()
			{
				var diff = new AssemblyDifference();
				diff.Name = "MyTestAssembly.dll";
				diff.FromVersion = "v1";
				diff.ToVersion = "v2";

				diff.Added(new TypeName(new FullyQualifiedName("Test.Added.Class1")));
				diff.Changed(new TypeDifference() { Name = "Test.Changed.Class2<T>" });
				diff.Removed(new TypeName(new FullyQualifiedName("Test.Removed.Class3")));
				diff.Obsolete(new TypeName(new FullyQualifiedName("Test.Obsolete.Class4")), "Do not use");

                diff.PercentChurn = 10;

				string output = diff.ToXml();

				Assert.Contains("<AssemblyDifference ", output);
				Assert.Contains("Name=\"MyTestAssembly.dll\"", output);
                Assert.Contains("PercentChurn=\"10\"", output);
                Assert.Contains("From=\"v1\"", output);
				Assert.Contains("To=\"v2\"", output);
				Assert.Contains("<AddedTypes>", output);
				Assert.Contains("</AddedTypes>", output);
				Assert.Contains("<ChangedTypes>", output);
				Assert.Contains("</ChangedTypes>", output);
				Assert.Contains("<ObsoleteTypes>", output);
				Assert.Contains("</ObsoleteTypes>", output);
				Assert.Contains("<RemovedTypes>", output);
				Assert.Contains("</RemovedTypes>", output);
				Assert.Contains("<Type Name=\"Class1\" Namespace=\"Test.Added\" FullName=\"Test.Added.Class1\" />", output);
				// changed
				Assert.Contains("<TypeNameReference ID=\"", output);
				Assert.Contains("TypeName=\"Test.Changed.Class2&lt;T&gt;\"", output);
                Assert.Contains("SafeName=\"Test.Changed.Class2T\"", output);
                // removed
				Assert.Contains("<Type Name=\"Class3\" Namespace=\"Test.Removed\" FullName=\"Test.Removed.Class3\" />", output);
                // obsolete
				Assert.Contains("<Type Name=\"Class4\" Namespace=\"Test.Obsolete\" FullName=\"Test.Obsolete.Class4\" Message=\"Do not use\" />", output);
			}

            [Fact, InMemoryTest]
            public void Omits_Null_Collections()
            {
                var diff = new AssemblyDifference();
                diff.Name = "MyTestAssembly.dll";
                diff.FromVersion = "v1";
                diff.ToVersion = "v2";

                diff.PercentChurn = 10;

                string output = diff.ToXml();

                Assert.Contains("<AssemblyDifference ", output);
                Assert.Contains("Name=\"MyTestAssembly.dll\"", output);
                Assert.Contains("PercentChurn=\"10\"", output);
                Assert.Contains("From=\"v1\"", output);
                Assert.Contains("To=\"v2\"", output);
                Assert.DoesNotContain("<AddedTypes", output);
                Assert.DoesNotContain("<ChangedTypes", output);
                Assert.DoesNotContain("<ObsoleteTypes", output);
                Assert.DoesNotContain("<RemovedTypes", output);
            }

		}

		public class TheSummaryIdentifierProperty
		{
			[Fact, InMemoryTest]
			public void Setting_SummaryIdent_Sets_SummaryIdentifier_On_Contained_Changes()
			{
				var diff = new AssemblyDifference();
				diff.Name = "MyTestAssembly.dll";
				diff.FromVersion = "v1";
				diff.ToVersion = "v2";

				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());

				const string SummaryId = "12345";
				diff.SummaryIdentifier = SummaryId;

				foreach (var detail in diff.ChangeDetails)
				{
					Assert.Equal(SummaryId, detail.SummaryIdentifier);
				}
			}
		}

		public class TheSummaryNameProperty
		{
			[Fact, InMemoryTest]
			public void Setting_SummaryName_Sets_SummaryName_On_Contained_Changes()
			{
				var diff = new AssemblyDifference();
				diff.Name = "MyTestAssembly.dll";
				diff.FromVersion = "v1";
				diff.ToVersion = "v2";

				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());

				const string SummaryName = "Index";
				diff.SummaryName = SummaryName;

				foreach (var detail in diff.ChangeDetails)
				{
					Assert.Equal(SummaryName, detail.SummaryName);
				}
			}
		}

		public class TheIdentifierProperty
		{
			[Fact, InMemoryTest]
			public void Setting_Identifier_Sets_AssemblyIdentifier_On_Contained_Changes()
			{
				var diff = new AssemblyDifference();
				diff.Name = "MyTestAssembly.dll";
				diff.FromVersion = "v1";
				diff.ToVersion = "v2";

				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());
				diff.Changed(new TypeDifference());

				const string AssemblyIdent = "0123456789";
				diff.Identifier = AssemblyIdent;

				foreach (var detail in diff.ChangeDetails)
				{
					Assert.Equal(AssemblyIdent, detail.AssemblyIdentifier);
				}
			}
		}
	}
}
